/**
 * This class is the blue print for all the requests that
 * are being communicated between different entities.
 */
package com.comp6231.common;

import java.net.DatagramPacket;

/**
 * @author Farzana Alam
 * 
 */
public class Request {

	/*
	 * Expected: Source ("Host Name ## UDP Port ## Entity Name"; eg. FrontEnd,
	 * CoordinatorReplica1, ...), Request ID ("Rxxxxxxx"), Operation Name
	 * (methodName for data), Arguments (for client requested methods)
	 */
	private String source;
	private String hostName;
	private int UDPPort;
	private String entityName;
	private String requestID;
	private String operation;

	// expected: parameter1 ## parameter2 ## .... ## parameterN
	private String operationArguments;
	private DatagramPacket packet;

	// these flags are used to handle FIFO queue
	private boolean locallyProcessed = false;
	private boolean remotelyProcessed = false;
	private boolean requestProcessd = false;

	// save the final response to be sent to the source for this request
	private String response = "";

	/**
	 * This one creates Request object from the following parameters
	 * 
	 * @param hostName
	 * @param UDPPort
	 * @param entityName
	 * @param requestID
	 * @param operation
	 * @param operationArguments
	 */
	public Request(String hostName, int UDPPort, String entityName,
			String requestID, String operation, String operationArguments) {
		this.hostName = hostName;
		this.UDPPort = UDPPort;
		this.entityName = entityName;
		this.requestID = requestID;
		this.operation = operation;
		this.operationArguments = operationArguments;
	}

	/**
	 * This constructor creates the Request object from a DtagramPAcket
	 * 
	 * @param packet
	 */
	public Request(DatagramPacket packet) {
		this.packet = packet;
		parsePacket();
	}

	/**
	 * This method gives the desired message format for sending DtagramPackets
	 * 
	 * @return
	 */
	public String createPacketString() {
		source = hostName + " ## " + UDPPort + " ## " + entityName;
		String cleanArguements = operationArguments.replace(',', '@');
		String packetString = source + ", " + requestID + ", " + operation
				+ ", " + cleanArguements;

		return packetString;
	}

	/**
	 * This method returns the current Request object after parsing the
	 * DatagramPacket that it received from the constructor.
	 * 
	 * @return
	 */
	public Request parsePacket() {

		String[] packetStrings = new String(packet.getData()).trim()
				.split(", ");
		source = packetStrings[0];
		requestID = packetStrings[1];
		operation = packetStrings[2];
		operationArguments = packetStrings[3].replace('@', ',');

		String[] tmp = source.split(" ## ");
		hostName = tmp[0];
		UDPPort = new Integer(tmp[1]);
		entityName = tmp[2];

		return this;
	}

	public String getResponse() {
		return response;
	}

	/**
	 * @param response
	 */
	public void setResponse(String response) {
		String[] responseReceived = response.split(" ## ");

		this.response = responseReceived[1];
	}

	/**
	 * This method checks if the Request object was successfully both locally
	 * and remotely. It is used for FIFO subsystem.
	 * 
	 * @return
	 */
	public boolean requestProcessedSuccessfully() {
		if (locallyProcessed && remotelyProcessed)
			requestProcessd = true;
		return requestProcessd;
	}

	public boolean isLocallyProcessed() {
		return locallyProcessed;
	}

	/**
	 * @param locallyProcessed
	 */
	public void setLocallyProcessed(boolean locallyProcessed) {
		this.locallyProcessed = locallyProcessed;
	}

	public boolean isRemotelyProcessed() {
		return remotelyProcessed;
	}

	/**
	 * @param processedInRemote1
	 */
	public void setRemotelyProcessd(boolean processedInRemote1) {
		this.remotelyProcessed = processedInRemote1;
	}

	public String getSource() {
		return source;
	}

	public String getHostName() {
		return hostName;
	}

	public int getUDPPort() {
		return UDPPort;
	}

	public String getEntityName() {
		return entityName;
	}

	public String getRequestID() {
		return requestID;
	}

	public String getOperation() {
		return operation;
	}

	public String getOperationArguments() {
		return operationArguments;
	}

	/**
	 * This method checks if the 2 Request objects are equal based on their
	 * unique Request ID.
	 */
	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Request))
			return false;
		Request req = (Request) obj;
		if (this.requestID.equalsIgnoreCase(req.getRequestID()))
			return true;
		return false;
	}

}
